gusucode.com > VC++ RingSDK界面库 > VC++ RingSDK界面库/code/libsrc/ringdows/ringchecklist.cpp

    /**********************************************************************
//
//
//        ##########                          ######  #########   # ######    #
//      #############                      ########### ######### #########  ###
//     ######## # ###  ##                 ############# ##    ## #####  # ####
//     ####  ##    ## ###                 ###     ### # #      #####   #####
//          #     ###  #            #     ##       ##  ##      ##     ###
//         ## ###### ##      ##  ####    ####          #       #     ##
//       #########  ###  ## ### #######   ######      ##      ##    ###
//      ######      ##  ######  ##  ##       ####     #      ##     ####
//     #######     ##   ###### ##  ###          ##   ##     ###    ######
//     #########   ##  ###### ## ######         ### ##    ###      #  #####
//    ##    ###### ####### ### #### ##  ## #######  ########      ##    ####
//    ##      #### ###  #  ### ### ##  ##########   ######       ##      ####
//   ##         ##                ##   #########    ####         #         ##
//               #              ###
//                              ##
//                             ###
//                             ##
//
//
//							临风程序界面类库 ringdows.lib
//作者:临风
//
//版本:1.0
//
//声明:本类库可以自由使用而不须对作者作出任何回报,但作者希望能得到
//		  你的鼓励和支持。你可以对类库源码作出修改和改进,但希望你能在
//		  修改的同时给作者一份同样的副本。
//		  本类库不得用于任何商业用途,如确实需要,请与作者联系。
//
//e-mail:ringphone@sina.com
//
//原文件名:ringchecklist.cpp
//
//说明:带选择框的ListBox控件控制
//
**********************************************************************/
#define MAKE_SELF_LIB
#define OEMRESOURCE
#include "ringdows.h"

RingCheckList::RingCheckList()
{
	m_hbmp = NULL;
}

RingCheckList::~RingCheckList()
{
	if(m_hbmp)
		DeleteObject(m_hbmp);
}

BOOL RingCheckList::Create(DWORD dwStyle,DWORD dwExStyle,LPCTSTR szInitText,UINT uId,int x,int y,int width,int height)
{
	dwStyle |= (LBS_HASSTRINGS|LBS_OWNERDRAWFIXED|LBS_NOTIFY|WS_VSCROLL);
	
	if(RingControls::Create(dwStyle,dwExStyle,szInitText,uId,x,y,width,height))
	{
		RingControls::SetOwnerDraw(FALSE,(UINT)0xFFFFFFFF);
		if(m_hbmp == NULL)
			CreateCheckBmp(NULL,GetItemHeight());
		return TRUE;
	}
	return FALSE;
}
	
BOOL RingCheckList::Create(UINT uId,int x/*=0*/,int y/*=0*/,int width/*=-999*/,int height/*=-999*/)
{
	DWORD dwExStyle = 0;
	if(width == -999 || height == -999)
		dwExStyle = RTV_FITPARENTSIZE;
	
	return Create(LBS_HASSTRINGS|LBS_OWNERDRAWFIXED|LBS_NOTIFY|WS_VSCROLL,
						dwExStyle,"",uId,x,y,width,height);
}

void RingCheckList::CreateCheckBmp(HDC hDC,int nSize)
{
	if(m_hbmp)
		DeleteObject(m_hbmp);

	BOOL bDelDC = FALSE;
	if(hDC == NULL)
	{
		hDC = GetDC(m_hWnd);
		bDelDC = TRUE;
	}
	m_nCheckSize = nSize;
	m_hbmp = CreateCompatibleBitmap(hDC,nSize*2,nSize);
	
	HBITMAP hbmCheck = LoadBitmap(NULL,(LPTSTR)OBM_CHECK);
	BITMAP bm;	
	HDC hDstDC = CreateCompatibleDC(hDC);
	HDC hSrcDC = CreateCompatibleDC(hDC);
	
	GetObject(hbmCheck,sizeof(BITMAP),&bm);
	
	SelectObject(hSrcDC,hbmCheck);
	SelectObject(hDstDC,m_hbmp);
	
	BitBlt(hDstDC,0,0,nSize*2,nSize,hSrcDC,0,0,WHITENESS);	
	Rectangle(hDstDC,2,2,nSize - 2,nSize - 2);
	Rectangle(hDstDC,nSize + 2,2,nSize*2 - 2,nSize - 2);

	BitBlt(hDstDC,nSize + 3,2,nSize,nSize,hSrcDC,0,0,SRCAND);
	
	DeleteDC(hSrcDC);
	DeleteDC(hDstDC);
	DeleteObject(hbmCheck);
	if(bDelDC)
		ReleaseDC(m_hWnd,hDC);
}

BOOL RingCheckList::Attach(HWND hWnd)
{
	//因为ListBox一旦创建其Style就不可改变,因此这里检测其Style
	//如果不是自绘则需要先Destroy然后再Create	
	DWORD style = GetWindowLong(hWnd,GWL_STYLE);
	style &= ~(LBS_SORT|LBS_MULTIPLESEL|LBS_MULTICOLUMN);
	DWORD st = LBS_HASSTRINGS|LBS_OWNERDRAWFIXED|LBS_NOTIFY;
	if((style & st) != st)
	{
		RECT rc;
		HWND hwnd;
		
		style |=	(st|WS_VSCROLL);
		
		DWORD exstyle = GetWindowLong(hWnd,GWL_EXSTYLE);
		
		GetWindowRect(hWnd,&rc);
		hwnd = ::GetParent(hWnd);
		
		ScreenToClient(hwnd,(LPPOINT)&rc);
		ScreenToClient(hwnd,(LPPOINT)&rc+1);
		
		m_ID = GetWindowLong(hWnd,GWL_ID);
		
		DestroyWindow(hWnd);
		
		if(RingControls::Create(style,exstyle,"",m_ID,
			rc.left,rc.top,rc.right-rc.left,rc.bottom-rc.top))
		{
			RingControls::SetOwnerDraw(FALSE,(UINT)0xFFFFFFFF);
			if(m_hbmp == NULL)
				CreateCheckBmp(NULL,GetItemHeight());
			return TRUE;
		}
	}
	else
		if(RingBaseWnd::Attach(hWnd))
		{
			RingControls::SetOwnerDraw(FALSE,(UINT)0xFFFFFFFF);
			if(m_hbmp == NULL)
				CreateCheckBmp(NULL,GetItemHeight());
			return TRUE;
		}
		
	return FALSE;
}

BOOL RingCheckList::OnDrawItem(LPDRAWITEMSTRUCT lpds)
{
	if(lpds->itemAction & ODA_FOCUS)
		return TRUE;

	RECT rc;	
	LPRINGCHECKLISTDATA lpData = (LPRINGCHECKLISTDATA)lpds->itemData;
	

	CopyRect(&rc,&lpds->rcItem);
	rc.left += m_nCheckSize;
	
	int ndc = SaveDC(lpds->hDC);
	
	SelectObject(lpds->hDC,m_brush);
	HDC hDC = CreateCompatibleDC(lpds->hDC);

	SelectObject(hDC,m_hbmp);

	if(lpData && lpds->itemData != LB_ERR)
		if(lpData->m_bChecked)
			BitBlt(lpds->hDC,0,rc.top,m_nCheckSize,m_nCheckSize,hDC,m_nCheckSize,0,SRCCOPY);
		else
			BitBlt(lpds->hDC,0,rc.top,m_nCheckSize,m_nCheckSize,hDC,0,0,SRCCOPY);

	if((lpds->itemState & ODS_SELECTED))
	{		
		::SetBkColor(lpds->hDC,GetSysColor(COLOR_HIGHLIGHT));
		::SetTextColor(lpds->hDC,GetSysColor(COLOR_HIGHLIGHTTEXT));
		ExtTextOut(lpds->hDC,0,0,ETO_OPAQUE,&rc,NULL,0,NULL);
	}
	else
		FillRect(lpds->hDC,&rc,m_brush);
	
	DrawText(lpds->hDC,GetText(lpds->itemID),GetTextLen(lpds->itemID),&rc,DT_LEFT|DT_SINGLELINE|DT_VCENTER);
	DeleteDC(hDC);
	RestoreDC(lpds->hDC,ndc);
	
	return TRUE;
}

//RingdowProc已对LB_GETITEMDATA和LB_SETITEMDATA进行处理使用户数据只能加到
//LPRINGCHECKLISTDATA的m_data字段,因此需提供原GetData和SetData的行为函数以
//使LPRINGCHECKLISTDATA能绑定到列表子项
LPRINGCHECKLISTDATA RingCheckList::GetPriData(int nIndex)
{
	LONG lpData = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,nIndex,0);
	if(lpData != LB_ERR)
		return (LPRINGCHECKLISTDATA)lpData;
	else
		return NULL;
}

BOOL RingCheckList::SetPriData(int nIndex,LPRINGCHECKLISTDATA lpData)
{
	if(lpData)
		return (BOOL)CallWindowProc(m_DefProc,m_hWnd,LB_SETITEMDATA,nIndex,(LPARAM)lpData);
	else
		return FALSE;
}

//检测选择状态
BOOL RingCheckList::IsItemChecked(int nIndex)
{
	if(nIndex == -1)
		nIndex = GetCurSel();

	LPRINGCHECKLISTDATA lpData = GetPriData(nIndex);
	if(lpData)
	{
		try
		{
			return lpData->m_bChecked;
		}
		catch(...)
		{
		}		
	}
	return FALSE;
}

//切换选择/非选择状态,ToggleItemCheck返回现状态,SetItemCheck返回原状态
BOOL RingCheckList::ToggleItemCheck(int nIndex)
{
	BOOL bRet = FALSE;

	if(nIndex == -1)
		nIndex = GetCurSel();
	
	LPRINGCHECKLISTDATA lpData = GetPriData(nIndex);
	if(lpData)
	{
		try
		{
			bRet = !lpData->m_bChecked;
			lpData->m_bChecked = bRet;
			SetPriData(nIndex,lpData);
		}
		catch(...)
		{
		}
	}
	return bRet;
}

BOOL RingCheckList::SetItemCheck(int nIndex,BOOL bCheck)
{
	BOOL bRet = FALSE;
	
	if(nIndex == -1)
		nIndex = GetCurSel();
	
	LPRINGCHECKLISTDATA lpData = GetPriData(nIndex);
	if(lpData)
	{
		try
		{
			bRet = lpData->m_bChecked;
			lpData->m_bChecked = bCheck;
			SetPriData(nIndex,lpData);
		}
		catch(...)
		{
		}
	}
	return bRet;
}

LRESULT RingCheckList::RingdowProc(HWND hWnd,RINGPARAMS param)
{
	switch(param.uMsg)
	{
		case WM_LBUTTONDOWN:
			if(param.mousept.y < GetCount() * GetItemHeight() && 
				param.mousept.x > 0 && param.mousept.x < m_nCheckSize)
			{
				int index = SendMessage(m_hWnd,LB_ITEMFROMPOINT,0,param.lParam);				
				RECT rc;
				ToggleItemCheck(index);				
				GetItemRect(index,&rc);
				InvalidateRect(m_hWnd,&rc,TRUE);
				return 0;
			}
			break;
		case WM_VSCROLL:
		case (WM_MOUSELAST+1)://=WM_MOUSEWHEEL
		{
			LRESULT res = RingControls::RingdowProc(hWnd,param);
			if(param.uMsg == (WM_MOUSELAST+1) || 
				(param.uMsg == WM_VSCROLL && param.wParam == SB_ENDSCROLL))
				InvalidateRect(m_hWnd,NULL,TRUE);
			return res;
		}
		case LB_ADDSTRING:
		case LB_INSERTSTRING:
		{
			LRESULT res = RingControls::RingdowProc(hWnd,param);
			
			if(res != LB_ERR && res != LB_ERRSPACE)
			{
				LPRINGCHECKLISTDATA lpData = (LPRINGCHECKLISTDATA)New(sizeof(RINGCHECKLISTDATA));
				if(lpData)
				{
					lpData->m_bChecked =	param.wParam;
					SetPriData(res,lpData);					
				}				
			}
			return res;
		}
		case LB_DELETESTRING:
		{			
			OnDelString(param.wParam);
			break;
		}
		case LB_RESETCONTENT:
		{
			int n = GetCount();
			for(int i=0;i<n;i++)
				OnDelString(i);
			break;
		}
		case LB_SETITEMDATA:
		{	
			LONG lpData = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,param.wParam,0);
			if(lpData != LB_ERR)
				if(lpData == 0)
					break;
				else
				{
					try
					{
						((LPRINGCHECKLISTDATA)lpData)->m_data = param.lParam;
						return TRUE;
					}
					catch(...)
					{						
					}
				}
			return LB_ERR;
		}
		case LB_GETITEMDATA:
		{	
			LONG lpData = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,param.wParam,0);
			if(lpData != LB_ERR)
			{
				if(lpData == 0)
					return 0;
				else
				{
					try
					{
						return ((LPRINGCHECKLISTDATA)lpData)->m_data;
					}
					catch(...)
					{
					}
				}
			}
			return LB_ERR;
		}
		//case WM_ERASEBKGND:
		case WM_WINDOWPOSCHANGED:
			return 0;
	}
	return RingControls::RingdowProc(hWnd,param);
}

//删除子项,检查数据RINGCHECKLISTDATA中有无用户设置的数据,有则将该数据
//替换RINGCHECKLISTDATA,释放RINGCHECKLISTDATA,函数返回后执行默认的删除
//子项操作
void RingCheckList::OnDelString(int index)
{
	LONG res = CallWindowProc(m_DefProc,m_hWnd,LB_GETITEMDATA,index,0);
	if(res != LB_ERR)
		if(res != 0)
		{
			LPRINGCHECKLISTDATA lpData = (LPRINGCHECKLISTDATA)res;
			if(lpData)
			try
			{
				if(lpData->m_data)
				{
					CallWindowProc(m_DefProc,m_hWnd,LB_SETITEMDATA,index,lpData->m_data);
					Del(lpData);
				}
			}
			catch(...)
			{
			}
		}
}

LRESULT RingCheckList::OnDestroy(RINGPARAMS& param)
{
	Clear();
	return DefaultProc(param);
}